﻿//-----------------------------------------------------------------------
// <copyright>
//     Copyright (c) Artur Mustafin. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Expressions.Compiler
{
    using System;

    /// <summary>
    /// Abstract entity
    /// </summary>
    public abstract class Entity<T> : IEquatable<Entity<T>>
    {
        private static int count;

        private readonly int _id;

        private readonly bool _optional;

        /// <summary>
        /// Gets a value indicating whether this <see cref="Entity"/> is optional.
        /// </summary>
        /// <value><c>true</c> if optional; otherwise, <c>false</c>.</value>
        internal bool Optional
        {
            get
            {
                return _optional;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Entity"/> class.
        /// </summary>
        /// <param name="optional">if set to <c>true</c> [optional].</param>
        protected Entity(bool optional = false)
        {
            _id = ++count;
            _optional = optional;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Entity"/> class.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="optional">if set to <c>true</c> [optional].</param>
        protected Entity(Entity<T> entity, bool optional = false)
        {
            _id = entity._id;
            _optional = optional;
        }


#if TRACE
        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>The name.</value>
        internal abstract string Name { get; }
#endif

        /// <summary>
        /// Parses the specified parser.
        /// </summary>
        /// <param name="parser">The parser.</param>
        /// <returns></returns>
        public abstract bool Parse(Parser<T> parser);

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.Value"/> to <see cref="Expressions.Compiler.Entity"/>.
        /// </summary>
        /// <param name="ch">The ch.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator Entity<T>(T ch)
        {
            return (Terminal<T>)ch;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.String"/> to <see cref="Expressions.Compiler.Entity"/>.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator Entity<T>(T[] s)
        {
            return (Terminal<T>)s;
        }

        /// <summary>
        /// Compares the specified instance.
        /// </summary>
        /// <param name="instance">The other.</param>
        /// <returns></returns>
        public bool Equals(Entity<T> instance)
        {
            if (instance != null)
            {
                return _id == instance._id;
            }
            return false;
        }
    }

    /// <summary>
    /// Abstract entity
    /// </summary>
    public abstract class Entity : IEquatable<Entity>
    {
        private static int count;

        private readonly int _id;

        private readonly bool _optional;

        /// <summary>
        /// Gets a value indicating whether this <see cref="Entity"/> is optional.
        /// </summary>
        /// <value><c>true</c> if optional; otherwise, <c>false</c>.</value>
        internal bool Optional
        {
            get
            {
                return _optional;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Entity"/> class.
        /// </summary>
        /// <param name="optional">if set to <c>true</c> [optional].</param>
        protected Entity(bool optional = false)
        {
            _id = ++count;
            _optional = optional;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Entity"/> class.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="optional">if set to <c>true</c> [optional].</param>
        protected Entity(Entity entity, bool optional = false)
        {
            _id = entity._id;
            _optional = optional;
        }

#if TRACE
        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>The name.</value>
        internal abstract string Name { get; }
#endif
        /// <summary>
        /// Parses the specified parser.
        /// </summary>
        /// <param name="parser">The parser.</param>
        /// <returns></returns>
        public abstract bool Parse(Parser parser);

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.Char"/> to <see cref="Expressions.Compiler.Entity"/>.
        /// </summary>
        /// <param name="ch">The ch.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator Entity(char ch)
        {
            return (Terminal)ch;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.String"/> to <see cref="Expressions.Compiler.Entity"/>.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator Entity(string s)
        {
            return (Terminal)s;
        }

        /// <summary>
        /// Compares the specified instance.
        /// </summary>
        /// <param name="instance">The other.</param>
        /// <returns></returns>
        public bool Equals(Entity instance)
        {
            if (instance != null)
            {
                return _id == instance._id;
            }
            return false;
        }
    }
}
